package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * 自定义切面：实现公共字段自动填充
 */
@Slf4j
@Aspect
@Component
public class AutoFillAspect {
  @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
  public void autoFillPointCut(){}

  /**
   * 前置通知中，实现公共字段的自动填充
   */
  @Before("autoFillPointCut()")
  public void autoFill(JoinPoint joinPoint){
    log.info("开始进行公共字段的自动填充: {}",joinPoint);
    // 1. 获取当前数据库操作的类型：update还是insert
    MethodSignature signature = (MethodSignature) joinPoint.getSignature(); // 获取方法签名对象
    AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);// 获取方法上的注解对象
    OperationType operationType = autoFill.value(); // 获取注解中的操作类型
    // 2. 获取到当前方法的参数：实体对象
    Object[] args = joinPoint.getArgs();
    if(args == null || args.length == 0){
      return;
    }
    Object entity = args[0]; // 获取第一个参数，即实体对象
    LocalDateTime now = LocalDateTime.now();
    Long id = BaseContext.getCurrentId();
    // 3. 根据不同的操作类型，给实体对象反射赋值
    if(operationType == OperationType.INSERT){
      try {
        Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
        Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
        Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
        Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
        // 通过反射来赋值
        setCreateTime.invoke(entity,now);
        setUpdateTime.invoke(entity,now);
        setCreateUser.invoke(entity,id);
        setUpdateUser.invoke(entity,id);
      } catch (Exception e) {
        e.printStackTrace();
      }
    } else {
      try {
        Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
        Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
        // 通过反射来赋值
        setUpdateTime.invoke(entity,now);
        setUpdateUser.invoke(entity,id);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
}
